<template>
  <div class="chat-core-wrap">
    <div
      class="message-list hide-scroller-bar"
      :style="{
        height: messageListHeight,
      }"
      id="chatListRef"
    >
      <div v-if="chatList.length > 0">
        <div v-for="(item, index) of chatList" :key="index">
          <div
            class="message-right"
            v-if="item.side == 'right' && showUserMessage"
          >
            <div class="message-main">
              <img
                :src="userInfo.avatar"
                alt=""
                class="avatar"
                v-if="userInfo.avatar"
              />
              <div class="avatar-icon" v-else>
                <UserOutlined />
              </div>
              <div class="message-content">
                <div class="message-card">
                  <div
                    class="message-text message-markdown-wrap"
                    :style="{ maxWidth: TextMaxWith + 'px' }"
                    v-highlight
                    v-html="item.content"
                  ></div>
                </div>
                <a-tooltip>
                  <template #title>复制</template>
                  <div
                    class="message-copy"
                    @click="$utils.copyText(item.content)"
                  >
                    <CopyOutlined />
                  </div>
                </a-tooltip>
              </div>
            </div>
          </div>
          <div class="message-left" v-if="item.side == 'left'">
            <div class="message-main" style="display: block">
              <img
                v-if="config.basic && config.basic.system_square_logo"
                :src="config.basic.system_square_logo"
                alt=""
                class="avatar"
                :style="item.isInput ? 'margin-bottom: 0px;' : ''"
              />
              <div
                class="message-content"
                style="max-width: 80%; display: inline-block"
              >
                <div class="message-card">
                  <div class="message-text message-markdown-wrap">
                    <MarkdownViewer
                      :markdown="item.content || '批量文本创作中，请等待'"
                      v-if="item.isInput"
                      class="message-text-content"
                      :input="item.isInput"
                      v-instruct="{ [INSTRUCT_QUICK_QUESTION]: submitQuestion }"
                    ></MarkdownViewer>
                    <MarkdownViewer
                      :markdown="item.content"
                      v-else-if="!item.is_textarea"
                      class="message-text-content"
                      v-instruct="{ [INSTRUCT_QUICK_QUESTION]: submitQuestion }"
                    ></MarkdownViewer>
                    <a-textarea
                      :style="{ width: TextMaxWith + 'px' }"
                      v-model:value="item.msg"
                      autosize
                      v-if="item.is_textarea"
                    />
                  </div>
                </div>
                <div
                  style="font-size: 12px; margin-top: 5px; color: #999"
                  v-if="!(item.special && item.special == 'vip')"
                >
                  以上内容为 AI 生成，不代表开发者立场
                </div>
                <template v-if="!item.isInput">
                  <div
                    v-if="item.special && item.special == 'vip'"
                    class="update-vip"
                  >
                    <a-button type="primary" @click="applyVip"
                      >升级会员</a-button
                    >
                  </div>
                  <div class="btn-list" v-else>
                    <div
                      class="message-copy"
                      @click="$utils.copyText(item.msg)"
                    >
                      <CopyOutlined />
                      <span class="txt">复制</span>
                    </div>
                    <div
                      v-if="
                        !item.special &&
                        item.special !== 'vip' &&
                        index > 0 &&
                        item.id
                      "
                      class="message-share"
                      @click="shareClick(index)"
                    >
                      <ShareAltOutlined />
                      <span class="txt">分享</span>
                    </div>
                    <div
                      v-if="
                        !item.special &&
                        item.special !== 'vip' &&
                        index > 0 &&
                        item.id
                      "
                      class="message-edit"
                      @click="editClick(item, index)"
                    >
                      <EditOutlined v-if="!item.is_textarea" />
                      <CheckOutlined v-else />
                      <span class="txt">{{
                        item.is_textarea ? "保存" : "编辑"
                      }}</span>
                    </div>
                    <div
                      class="message-down-load"
                      @click="downLoadClick(item, index)"
                      v-if="
                        !item.special &&
                        item.special !== 'vip' &&
                        index > 0 &&
                        item.id
                      "
                    >
                      <DownloadOutlined v-if="item.downLoad" />
                      <LoadingOutlined v-else />
                      <span class="txt">下载</span>
                    </div>
                    <div
                      v-if="
                        !item.special &&
                        item.special !== 'vip' &&
                        index > 0 &&
                        item.id
                      "
                      class="message-audio"
                      @click="audioClick(item, index)"
                    >
                      <cu-icon
                        class="icon"
                        type="icon-yuyinbofang"
                        style="font-size: 20px"
                        v-if="item.audio && !item.audioLoading"
                      ></cu-icon>
                      <LoadingOutlined
                        v-else-if="item.audio && item.audioLoading"
                      />
                      <PauseCircleOutlined
                        style="font-size: 18px; color: #999"
                        v-else
                        @click.stop="suspendAudio(item)"
                      />

                      <span class="txt">{{
                        item.audio ? "语音播放" : "正在播放"
                      }}</span>
                    </div>
                    <div
                      class="message-continue message-continue-hover"
                      @click="chatContinueClick(item, index)"
                      v-if="
                        !item.special &&
                        item.special !== 'vip' &&
                        index > 0 &&
                        index == chatList.length - 1
                      "
                    >
                      <UngroupOutlined />
                      <span class="txt">继续回答</span>
                    </div>
                  </div>
                </template>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div
        class="recommend-list"
        v-else-if="recommendList.length > 0 && showRecommendList"
      >
        <div style="width: 100%; position: relative">
          <div class="recommend-title">🔥 热门提问</div>
          <a-button
            type="link"
            class="refresh-button"
            @click="getRecommendList"
          >
            <template #icon><ReloadOutlined /></template>
            <span>换一批</span>
          </a-button>
          <div class="cate-list">
            <div
              v-for="(cate, cateIndex) of recommendList"
              :key="cateIndex"
              class="cate-column"
            >
              <div class="cate-title">
                <img :src="cate.cat_icon" class="cate-icon" />
                <span> {{ cate.cat_name }}</span>
              </div>
              <div
                v-for="(item, index) of cate.content_list"
                :key="index"
                class="cate-item-card"
                @click="recommendAddChat(item)"
              >
                <div class="cate-item-content">{{ item }}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="chat-footer" v-if="showInput">
      <div class="button-list" v-if="showBtnList">
        <a-button
          type="primary"
          style="border-radius: 6px; width: 110px; height: 35px"
          @click="loginHandle(() => addNewChat())"
        >
          <template #icon><PlusOutlined /></template>
          新建对话
        </a-button>
        <a-button
          type="primary"
          ghost
          style="
            border-radius: 6px;
            width: 110px;
            height: 35px;
            margin-left: 12px;
          "
          @click="promptsModalVisible = true"
        >
          <template #icon><ThunderboltOutlined /></template>
          提示词
        </a-button>
        <a-button
          type="primary"
          ghost
          style="
            border-radius: 6px;
            width: 110px;
            height: 35px;
            margin-left: 12px;
          "
          @click="loginHandle(() => (chatHistoryVisible = true))"
        >
          <template #icon><UnorderedListOutlined /></template>
          对话记录
        </a-button>
      </div>
      <div class="chat-input-wrap">
        <a-textarea
          v-model:value="question"
          placeholder="有问题尽管问我... (Shift + Enter 换行)"
          class="chat-input"
          @pressEnter="onQuestionInputEnter"
          ref="questionInputRef"
        ></a-textarea>
        <a-button
          type="primary"
          class="chat-submit-button"
          :disabled="question.length == 0 || submitDisabled"
          @click="submit()"
          >发送</a-button
        >
      </div>

      <a-tooltip v-if="showDisclaimer">
        <template #title
          >该服务处于前沿探索阶段，您应当合法合规使用本服务，并承担由此产生的所有责任。我们对您的使用不做保证且不承担任何责任。</template
        >
        <div class="disclaimer-wrap" @click="disclaimerClick">
          <ExclamationCircleOutlined />
          免责声明
        </div>
      </a-tooltip>
    </div>

    <div
      class="stop-button-wrap"
      :style="{
        height: footerHeight,
      }"
      v-if="AiInputting"
    >
      <a-button
        type="primary"
        shape="round"
        @click="stopChat"
        style="width: 140px"
      >
        <PauseOutlined />
        停止回答
      </a-button>
    </div>

    <LoginModal
      :visible="loginVisible"
      @onClose="loginVisible = false"
      @loginCallback="loginCallback"
    />
    <memberShip :visible="showMemberShip" @close="closeMemberShip" />

    <!-- 图片预览 -->
    <a-modal v-model:visible="modalVisible" title="海报分享" :footer="null">
      <div style="text-align: center">
        <a-spin :spinning="spinning">
          <img :src="shareData.url" style="width: 420px" id="h5Qrcode" />
        </a-spin>
        <div>
          <a-button
            type="link"
            ghost
            style="margin-top: 5px"
            @click="downloadImage"
            >下载</a-button
          >
        </div>
      </div>
    </a-modal>

    <PromptUse
      :visible="promptsModalVisible"
      @onClose="promptsModalVisible = false"
      @onSearchSelect="usePrompt"
    />

    <ChatHistory
      :visible="chatHistoryVisible"
      @useChat="useHistoryChat"
      @onClose="chatHistoryVisible = false"
      @historyDelete="historyDelete"
    />

    <PromptReplace
      :prompt="currentPrompt"
      :visible="promptReplaceVisible"
      @onClose="promptReplaceClose"
      @replaceCallback="replaceCallback"
    />
  </div>
</template>

<script>
import {
  defineComponent,
  reactive,
  toRefs,
  computed,
  watch,
  toRaw,
  h,
  onBeforeUnmount,
  createVNode,
  onUnmounted,
  ref,
  nextTick,
} from "vue";
import request from "../../common/utils/request";
import store from "../../store/index";
import { useRoute, useRouter } from "vue-router";
import utils from "../../common/utils/utils";
import { Modal, notification, message } from "ant-design-vue";
import {
  CopyOutlined,
  ReloadOutlined,
  PauseOutlined,
  UserOutlined,
  ExclamationCircleOutlined,
  ShareAltOutlined,
  PlusOutlined,
  ThunderboltOutlined,
  UnorderedListOutlined,
  EditOutlined,
  DownloadOutlined,
  CheckOutlined,
  LoadingOutlined,
  PauseCircleOutlined,
  UngroupOutlined,
} from "@ant-design/icons-vue";

import defaultSetting from "../../common/utils/defaultSetting";
import { useFilter } from "../../hooks/filter";
import base64 from "../../common/utils/base64";
import memberShip from "../../views/vip/modules/memberShip.vue";
import { streamFetch } from "../../common/utils/streamFetch";
import PromptUse from "../../components/PromptUse/index.vue";
import ChatHistory from "../../components/ChatHistory/index.vue";
import PromptReplace from "../../components/PromptReplace/index.vue";
import MarkdownViewer from "../MarkdownViewer/index.vue";
import { INSTRUCT_QUICK_QUESTION } from "../MarkdownViewer/instruct";

export default defineComponent({
  name: "ChatCore",
  components: {
    CopyOutlined,
    ReloadOutlined,
    PauseOutlined,
    UserOutlined,
    memberShip,
    ExclamationCircleOutlined,
    ShareAltOutlined,
    PlusOutlined,
    ThunderboltOutlined,
    UnorderedListOutlined,
    PromptUse,
    ChatHistory,
    PromptReplace,
    EditOutlined,
    DownloadOutlined,
    CheckOutlined,
    LoadingOutlined,
    PauseCircleOutlined,
    UngroupOutlined,
    MarkdownViewer,
  },

  props: {
    TextMaxWith: {
      type: [Number, String],
      default: 680,
    },
    chatId: {
      type: [Number, String],
      default: null,
    },
    userAutoMsg: {
      type: String,
      default: "",
    },
    visible: {
      type: Boolean,
      default: false,
    },
    showUserMessage: {
      type: Boolean,
      default: true,
    },
    showRecommendList: {
      type: Boolean,
      default: true,
    },
    showInput: {
      type: Boolean,
      default: true,
    },
    defaultQuestion: {
      type: String,
      default: "",
    },
    showBtnList: {
      type: Boolean,
      default: false,
    },
    chatPromptId: {
      type: [Number, String],
      default: 0,
    },
    chatDataProcess: {
      type: Function,
      default: (chatList) => chatList,
    },
    appId: {
      type: String,
      required: true,
    },
  },

  setup(props, context) {
    const route = useRoute();
    const router = useRouter();
    const state = reactive({
      showMemberShip: false,
      config: {},
      userInfo: {},
      question: "",
      submitDisabled: false,
      pluginList: [],
      chatInfo: {},
      chatList: [],
      recommendList: [],
      loginVisible: false,
      AiInputting: false, //AI回复中（可以停止回答）

      showDisclaimer: true,
      disclaimer_url: "",

      modalVisible: false,
      shareData: {},
      spinning: false,

      promptsModalVisible: false,
      chatHistoryVisible: false,

      promptReplaceVisible: false,
      currentPrompt: {},
    });

    const { filterWords, filter } = useFilter();

    const uuidv4 = () => {
      let d = new Date().getTime();
      var uuid = "uuid-xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
        /[xy]/g,
        function (c) {
          let r = (d + Math.random() * 16) % 16 | 0;
          d = Math.floor(d / 16);
          return (c == "x" ? r : (r & 0x3) | 0x8).toString(16);
        }
      );
      return uuid;
    };

    const scrollToBottom = () => {
      let chatListRef = document.getElementById("chatListRef");
      if (chatListRef) {
        chatListRef.scrollTo(0, chatListRef.scrollHeight);
      }
    };

    const addChat = () => {
      let params = {
        title: state.question,
        team_id: utils.getCurrentTeam() || 0,
      };
      request
        .post("/work_ai", "/chat/add", {
          ...params,
        })
        .then((res) => {
          if (res.chat_id) {
            state.chatId = res.chat_id;
            sendMsg();
            context.emit("addChat", res.chat_id);
          }
        });
    };

    const questionInputRef = ref(null);

    const loginHandle = (fn) => {
      utils.checkLogin().then((isLogin) => {
        if (!isLogin) {
          state.loginVisible = true;
          return;
        }

        fn && fn();
      });
    };

    const submit = (chatContinue = false) => {
      loginHandle(() => {
        state.currentPrompt = {};

        if (!state.chatId) {
          addChat();
        } else {
          sendMsg(null, chatContinue);
        }
      });
    };

    const sendMsg = (defaultQuestion, chatContinue = false) => {
      let question = filter.replaceSensitiveWord(state.question, 1, "*");
      if (defaultQuestion) {
        question = filter.replaceSensitiveWord(defaultQuestion, 1, "*");
      }

      state.chatList.push({
        side: "right",
        content: question,
        msg: question,
        uuid: uuidv4(),
        downLoad: true,
        audio: true,
        audioLoading: false,
      });

      state.submitDisabled = true;
      state.showDisclaimer = false;
      console.log("state.chatList", state.chatList);
      let params = {
        chat_id: state.chatId,
        question: question,
        team_id: utils.getCurrentTeam() || 0,
      };
      state.question = "";
      request
        .post("/work_ai", "/chat/send_message", { ...params })
        .then((res) => {
          getMsg(res.id, chatContinue);
        })
        .catch((err) => {
          if (err.code == 3601) {
            state.chatList.push({
              side: "left",
              content: err.msg,
              msg: err.msg,
              uuid: uuidv4(),
              special: "vip",
            });
            context.emit("eventSourceFinish");
          }
        });
    };

    let scrollTimer = null;

    let controller = ref(new AbortController());

    const getMsg = async (msgId, chatContinue = false) => {
      state.chatList.push({
        side: "left",
        content: "",
        msg: "",
        uuid: uuidv4(),
        isInput: true,
        downLoad: true,
        audio: true,
        audioLoading: false,
        id: msgId,
      });

      scrollTimer = setInterval(() => {
        scrollToBottom();
      }, 500);

      let msgIndex = state.chatList.length - 1;

      let BASE_URL = defaultSetting.requestDomain;
      if (process.env.NODE_ENV === "development") {
        BASE_URL = BASE_URL + "/api";
      }

      state.AiInputting = true;

      const abortSignal = new AbortController();
      controller.value = abortSignal;

      let params = {
        chat_id: state.chatId,
        message_id: msgId,
        app_id: props.appId,
      };

      if (props.chatPromptId) {
        params.prompt_words_id = props.chatPromptId;
      }

      if (state.currentPrompt.id) {
        params.prompt_words_id = state.currentPrompt.id;
      }

      params.continue = chatContinue;

      const { responseText } = await streamFetch({
        url: `${BASE_URL}/work_ai/chat/event_stream`,
        data: params,
        onMessage: (text) => {
          if (utils.isJSONStr(text)) {
            //这里有错误
            let res = JSON.parse(text);

            if (utils.isObject(res) && res.msg) {
              message.error(res.msg);
              return;
            }
          }

          state.chatList[msgIndex].msg += text;
          state.chatList[msgIndex].content += text;
          state.chatList[msgIndex].msg = filter.replaceSensitiveWord(
            state.chatList[msgIndex].msg,
            1,
            "x"
          );
          state.chatList[msgIndex].content = filter.replaceSensitiveWord(
            state.chatList[msgIndex].content,
            1,
            "x"
          );
        },
        abortSignal,
      }).catch((err) => {
        console.log(err);

        return {
          responseText: false,
        };
      });

      if (
        (utils.isJSONStr(responseText) || !responseText) &&
        state.chatList[msgIndex].msg == ""
      ) {
        state.chatList[msgIndex].isInput = false;
        state.chatList[msgIndex].msg = "使用的人过多了，您再提问一下。";
        state.chatList[msgIndex].content = "使用的人过多了，您再提问一下。";
      } else {
        state.chatList[msgIndex].isInput = false;
        state.chatList[msgIndex].msg = state.chatList[msgIndex].content;
      }

      state.submitDisabled = false;
      state.AiInputting = false;

      context.emit(
        "eventSourceFinish",
        !utils.isJSONStr(responseText) && responseText
          ? state.chatList[msgIndex].msg
          : ""
      );

      //判断要不要请求接口
      if (
        state.chatInfo.plugin_id &&
        !utils.isJSONStr(responseText) &&
        responseText
      ) {
        request.get(
          "/work_ai",
          "/plugin/getData",
          {
            chat_id: state.chatId,
            message_id: msgId,
            plugin_id: state.chatInfo.plugin_id,
          },
          (pluginData) => {
            if (pluginData.content) {
              state.chatList[msgIndex].content = pluginData.content;
            }
          }
        );
      }

      //停止前让滑动至最后一屏
      setTimeout(() => {
        clearInterval(scrollTimer);
        scrollTimer = null;
      }, 1000);

      abortSignal.signal.aborted && (await utils.delay(600));
    };

    const getRecommendList = () => {
      request.get("/work_ai", "/hotChat/recommendList", {}).then((res) => {
        state.recommendList = res.list;
        console.log("state.recommendList: ", state.recommendList);
      });
    };

    const getMessageList = () => {
      if (state.chatId) {
        request
          .get("/work_ai", "/chat/message_list", {
            chat_id: state.chatId,
          })
          .then((res) => {
            res = props.chatDataProcess(res);
            state.chatInfo = res.chat;

            //如果有引导句，则使用
            if (res.chat.user_msg) {
              state.chatList.push({
                side: "left",
                content: res.chat.user_msg,
                msg: res.chat.user_msg,
                uuid: uuidv4(),
                downLoad: true,
                audioLoading: false,
                audio: true,
              });
            }

            for (let i in res.list) {
              if (res.list[i].human) {
                state.chatList.push({
                  side: "right",
                  msg: res.list[i].human,
                  content: res.list[i].human,
                  uuid: uuidv4(),
                  downLoad: true,
                  audio: true,
                  audioLoading: false,
                  id: res.list[i].id,
                });
              }
              if (res.list[i].ai) {
                console.log(res.list[i], {
                  downLoad: res.list[i].downLoad === false ? false : true,
                  audioLoading:
                    res.list[i].audioLoading === true ? true : false,
                  audio: res.list[i].audio === false ? false : true,
                  is_textarea: res.list[i].is_textarea === true ? true : false,
                });
                state.chatList.push({
                  side: "left",
                  msg: res.list[i].ai_rich
                    ? res.list[i].ai_rich
                    : res.list[i].ai,
                  content: res.list[i].ai_rich
                    ? res.list[i].ai_rich
                    : res.list[i].ai,
                  uuid: uuidv4(),
                  id: res.list[i].id,
                  downLoad: true,
                  audioLoading: false,
                  audio: true,
                  is_textarea: false,
                });
              }
            }

            // 默认到最底部
            nextTick(() => {
              scrollToBottom();
            });

            if (res.list.length == 0) {
              if (props.userAutoMsg && props.userAutoMsg.length > 0) {
                sendMsg(props.userAutoMsg);
              } else if (
                props.defaultQuestion &&
                props.defaultQuestion.length > 0
              ) {
                sendMsg(props.defaultQuestion);
              } else if (state.currentPrompt.content) {
                sendMsg(state.currentPrompt.content);
              } else if (state.question) {
                sendMsg();
              }
            } else {
              state.submitDisabled = false;
            }
          });
      }
    };

    const init = () => {
      state.chatList = [];
      utils.getUserInfo().then((userInfo) => {
        if (userInfo && userInfo.id) {
          state.userInfo = userInfo;
        }
      });

      store.dispatch("GetConfigInfo").then((config) => {
        if (config && config.basic && config.basic.system_name) {
          state.config = config;
        }
      });

      request.get("/work_ai", "/config").then(async (res) => {
        if (res.list && res.list.sensitive_words) {
          filterWords.value = base64
            .decode(res.list.sensitive_words)
            .split("&^&");
        }
      });

      if (props.showRecommendList) {
        getRecommendList();
      }

      if (props.chatId) {
        state.chatId = props.chatId;
      }
      getMessageList();
    };

    init();

    watch(
      () => props.visible,
      (val) => {
        if (val) {
          init();
        }
      }
    );

    watch(
      () => props.chatId,
      (val) => {
        if (val) {
          state.chatList = [];
          getMessageList();
        }
      }
    );

    onUnmounted(() => {
      // 组件销毁时停止eventSource
      controller.value.abort();

      if (scrollTimer) {
        //停止前让滑动至最后一屏
        clearInterval(scrollTimer);
        scrollTimer = null;
      }
    });

    const recommendAddChat = (title) => {
      loginHandle(() => {
        state.question = title;
        submit();
      });
    };

    const onQuestionInputEnter = (e) => {
      if (!e.shiftKey) {
        if (state.submitDisabled || !state.question || !state.question.trim()) {
          return;
        }
        e.preventDefault();
        questionInputRef.value.blur();
        submit();
      }
    };

    const loginCallback = () => {
      state.loginVisible = false;
      router.go(0);
    };

    const applyVip = () => {
      state.showMemberShip = true;
      // router.push({
      //   name: "ActivateMembership",
      // });
    };

    const closeMemberShip = () => {
      state.showMemberShip = false;
    };

    const stopChat = () => {
      controller.value.abort();
      //停止前让滑动至最后一屏
      clearInterval(scrollTimer);
      scrollTimer = null;
      let msgIndex = state.chatList.length - 1;
      state.chatList[msgIndex].isInput = false;
      state.submitDisabled = false;
      state.AiInputting = false;
      context.emit("eventSourceFinish");
    };

    const disclaimerClick = () => {
      if (state.disclaimer_url) {
        window.open(state.disclaimer_url, "_blank");
      } else {
        request.get("/work_ai", "/config").then((res) => {
          if (res.list) {
            state.disclaimer_url = res.list.disclaimer_url;
            window.open(state.disclaimer_url, "_blank");
          }
        });
      }
    };

    const shareClick = (index) => {
      state.spinning = true;
      state.modalVisible = true;
      let app_id = 0;
      if (route.path.includes("scene")) {
        app_id = route.path.split("scene")[1];
      } else {
        app_id = 0;
      }

      if (state.chatList[index].msg) {
        request
          .post("/work_ai", "/chat/poster", {
            question: state.chatList[index - 1].msg,
            content: state.chatList[index].msg,
            app_id: Number(app_id) || undefined,
          })
          .then((res) => {
            state.shareData = res.data;
            state.spinning = false;
          });
      }
    };

    // 编辑
    const editClick = (item, index) => {
      if (!item.msg) {
        message.warn("输入框不能为空");
        return;
      }
      item.is_textarea = !item.is_textarea;
      if (!item.is_textarea && state.chatList[index].id) {
        request
          .put("/work_ai", "/chat/message/update", {
            message_id: state.chatList[index].id,
            chat_id: state.chatId,
            ai_txt: item.msg,
          })
          .then((res) => {
            state.chatList[index].content = item.msg;
            item.is_textarea = false;
            message.success("修改成功");
          });
        return;
      }
    };

    // 下载回答
    const downLoadClick = (item, index) => {
      if (!item.downLoad) {
        return;
      }
      if (state.chatList[index].id && item.downLoad) {
        item.downLoad = false;
        request
          .get("/work_ai", "/chat/message/download", {
            message_id: state.chatList[index].id,
            chat_id: state.chatId,
          })
          .then((res) => {
            item.downLoad = true;
            window.open(res.result.url);
          })
          .catch(() => {
            item.downLoad = false;
          });
      }
    };

    const audio = new Audio();
    let timer = null;
    const audioClick = (item, index) => {
      if (state.chatList[index].id && item.audio) {
        state.chatList.forEach((item) => {
          if (item.id !== state.chatList[index].id && item.side == "left") {
            item.audio = true;
            item.audioLoading = false;
          }
        });
        let second = 0;
        if (item.audioLoading) {
          return;
        }
        item.audioLoading = true;
        request
          .post("/work_ai", "/chat/message/voice", {
            message_id: state.chatList[index].id,
            chat_id: state.chatId,
          })
          .then((res) => {
            item.audioLoading = false;
            audio.src = res.result.url;
            audio.play();
            item.audio = false;
            let playPromise = audio.play();
            if (playPromise) {
              playPromise
                .then(() => {
                  // 音频加载成功
                  // 音频的播放需要耗时
                  clearInterval(timer);
                  audio.oncanplaythrough = function () {
                    // 获取时长，并向下取整
                    second = Math.floor(audio.duration);
                    console.log(second, "总时长");
                    timer = setInterval(() => {
                      second--;
                      if (second < 0) {
                        audio.pause();
                        clearInterval(timer);
                        item.audio = true;
                      }
                      console.log(second);
                    }, 1000);
                  };
                })
                .catch((e) => {
                  // 音频加载失败
                  item.audio = true;
                  item.audioLoading = false;
                });
            }
          })
          .catch(() => {
            item.audio = true;
            item.audioLoading = false;
          });
      }
    };

    // 暂停播放
    const suspendAudio = (item) => {
      item.audio = true;
      audio.pause();
      clearInterval(timer);
    };

    const downloadImage = () => {
      var image = new Image();
      image.setAttribute("crossOrigin", "anonymous");
      image.onload = function () {
        var canvas = document.createElement("canvas");
        canvas.width = image.width;
        canvas.height = image.height;
        var context = canvas.getContext("2d");
        context.drawImage(image, 0, 0, image.width, image.height);
        var url = canvas.toDataURL("image/png");
        // 生成一个a元素
        var a = document.createElement("a");
        // 创建一个单击事件
        var event = new MouseEvent("click");

        // 将a的download属性设置为我们想要下载的图片名称，若name不存在则使用‘下载图片名称’作为默认名称
        a.download = "海报分享";
        // 将生成的URL设置为a.href属性
        a.href = url;

        // 触发a的单击事件
        a.dispatchEvent(event);
      };
      image.src = state.shareData.url;
    };

    // 新建对话
    const addNewChat = () => {
      context.emit("newChat");
    };

    const useHistoryChat = (chat) => {
      state.chatId = chat.chat_id;
      state.userAutoMsg = chat.title;
      init();
      state.chatHistoryVisible = false;
    };

    const historyDelete = (chat, clearAll) => {
      // 如果删除的历史记录是正在对话的聊天，则清除聊天
      if ((chat && chat.chat_id == state.chatId) || clearAll) {
        state.chatHistoryVisible = false;
        context.emit("newChat");
      }
    };

    const messageListHeight = computed(() => {
      let height = "";
      if (props.showInput) {
        if (props.showBtnList && state.showDisclaimer) {
          height = "calc(100% - 133px)";
        } else {
          if (props.showBtnList) {
            height = "calc(100% - 117px)";
          } else if (state.showDisclaimer) {
            height = "calc(100% - 86px)";
          } else {
            height = "calc(100% - 70px)";
          }
        }
      } else {
        height = "100%";
      }
      return height;
    });

    const footerHeight = computed(() => {
      let height = "";
      if (props.showInput) {
        if (props.showBtnList && state.showDisclaimer) {
          height = "123px";
        } else {
          if (props.showBtnList) {
            height = "107px";
          } else if (state.showDisclaimer) {
            height = "76px";
          } else {
            height = "60px";
          }
        }
      } else {
        height = "60px";
      }
      return height;
    });

    // 使用提示词
    const usePrompt = (item) => {
      loginHandle(() => {
        state.currentPrompt = item;
        if (item.content_matches && item.content_matches.length > 0) {
          state.promptReplaceVisible = true;
        } else {
          promptAddChat();
        }
      });
    };

    const replaceCallback = (list) => {
      loginHandle(() => {
        // 根据替换后的关键词，组装提示词内容
        if (list && list.length > 0) {
          list.forEach((item) => {
            state.currentPrompt.content = state.currentPrompt.content.replace(
              item[0],
              item[1]
            );
          });
          promptAddChat();
        }
      });
    };

    const promptAddChat = () => {
      state.promptReplaceVisible = false;

      let params = {
        title: state.currentPrompt.content,
        team_id: utils.getCurrentTeam() || 0,
      };
      request
        .post("/work_ai", "/chat/add", {
          ...params,
        })
        .then((res) => {
          if (res.chat_id) {
            state.chatId = res.chat_id;
            state.chatPromptId = state.currentPrompt.id;
            state.promptsModalVisible = false;

            init();
          }
        });
    };

    const promptReplaceClose = () => {
      state.promptReplaceVisible = false;
      state.currentPrompt = {};
    };

    onUnmounted(() => {
      audio.pause();
      clearInterval(timer);
    });

    const chatContinueClick = () => {
      submitQuestion("继续回答", true);
    };

    const submitQuestion = (question, chatContinue = false) => {
      state.question = question;
      submit(chatContinue);
    };

    return {
      ...toRefs(state),
      submit,
      getRecommendList,
      recommendAddChat,
      loginCallback,
      applyVip,
      stopChat,
      questionInputRef,
      onQuestionInputEnter,
      closeMemberShip,
      disclaimerClick,
      shareClick,
      downloadImage,
      addNewChat,
      usePrompt,
      useHistoryChat,
      historyDelete,
      messageListHeight,
      footerHeight,
      replaceCallback,
      promptReplaceClose,
      downLoadClick,
      audioClick,
      editClick,
      suspendAudio,
      chatContinueClick,
      submitQuestion,

      INSTRUCT_QUICK_QUESTION,
      loginHandle,
    };
  },
});
</script>

<style lang="less" scoped>
.chat-core-wrap {
  width: 100%;
  height: 100%;
  position: relative;

  .stop-button-wrap {
    width: 100%;
    position: absolute;
    left: 0;
    bottom: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(200, 200, 200, 0.5);
    border-radius: 8px;
  }

  .message-list {
    width: 100%;
    overflow: hidden auto;

    .message-left {
      padding: 10px 0;

      .message-main {
        display: flex;

        .avatar {
          width: 40px;
          height: 40px;
          object-fit: cover;
          border-radius: 50%;
          margin-right: 10px;
          margin-bottom: 100px;
        }

        .message-content {
          position: relative;
          padding-right: 40px;

          .message-card {
            background-color: #fff;
            padding: 10px 20px;
            border-radius: 8px;

            .message-text {
              .message-text-content {
                // white-space: pre-wrap;

                &:deep(p) {
                  // margin-bottom: 0px;
                }
              }

              .message-text-focus {
                display: inline-block;
                width: 2px;
                font-weight: 900;
                color: #5a54f9;
                line-height: 24px;
                animation: 1s infinite twinkle;
              }

              @keyframes twinkle {
                0% {
                  opacity: 1; //透明程度
                }

                100% {
                  transform: scale(1);
                  opacity: 0;
                }
              }
            }
          }
          .btn-copy {
            display: none;
          }
          .btn-list {
            display: flex;
            margin-top: 10px;
            .message-copy {
              background-color: #fff;
              width: 30px;
              height: 30px;
              border-radius: 50%;
              display: flex;
              justify-content: center;
              align-items: center;
              cursor: pointer;
              color: #999;
              margin-right: 10px;

              &:hover {
                color: #333;
              }
              .txt {
                display: none;
              }
            }
            .message-copy:hover {
              background-color: #fff;
              width: 65px;
              height: 30px;
              border-radius: 30px;

              &:hover {
                color: #333;

                .txt {
                  display: block;
                  color: #333;
                  margin-left: 5px;
                }
              }
            }

            .message-share {
              background-color: #fff;
              width: 30px;
              height: 30px;
              border-radius: 50%;
              display: flex;
              justify-content: center;
              align-items: center;
              cursor: pointer;
              color: #999;
              margin-right: 10px;
              .txt {
                display: none;
                color: #333;
                margin-left: 5px;
              }
            }
            .message-share:hover {
              background-color: #fff;
              width: 65px;
              height: 30px;
              border-radius: 30px;

              &:hover {
                color: #333;

                .txt {
                  display: block;
                  color: #333;
                  margin-left: 5px;
                }
              }
            }
            .message-edit {
              background-color: #fff;
              width: 30px;
              height: 30px;
              border-radius: 50%;
              display: flex;
              justify-content: center;
              align-items: center;
              cursor: pointer;
              color: #999;
              margin-right: 10px;
              .txt {
                display: none;
              }
            }
            .message-edit:hover {
              background-color: #fff;
              width: 65px;
              height: 30px;
              border-radius: 30px;

              &:hover {
                color: #333;

                .txt {
                  display: block;
                  color: #333;
                  margin-left: 5px;
                }
              }
            }
            .message-down-load {
              background-color: #fff;
              width: 30px;
              height: 30px;
              border-radius: 50%;
              display: flex;
              justify-content: center;
              align-items: center;
              cursor: pointer;
              color: #999;
              margin-right: 10px;
              .txt {
                display: none;
              }
            }
            .message-down-load:hover {
              background-color: #fff;
              width: 65px;
              height: 30px;
              border-radius: 30px;

              &:hover {
                color: #333;

                .txt {
                  display: block;
                  color: #333;
                  margin-left: 5px;
                }
              }
            }
            .message-audio {
              background-color: #fff;
              width: 30px;
              height: 30px;
              border-radius: 50%;
              display: flex;
              justify-content: center;
              align-items: center;
              cursor: pointer;
              color: #999;
              margin-right: 10px;
              .txt {
                display: none;
              }
            }
            .message-audio:hover {
              background-color: #fff;
              width: 95px;
              height: 30px;
              border-radius: 30px;

              &:hover {
                color: #333;

                .txt {
                  display: block;
                  color: #333;
                  margin-left: 5px;
                }
              }
            }
            .message-continue {
              background-color: #fff;
              width: 30px;
              height: 30px;
              border-radius: 50%;
              display: flex;
              justify-content: center;
              align-items: center;
              cursor: pointer;
              color: #999;
              .txt {
                display: none;
              }
            }
            .message-continue:hover,
            .message-continue-hover {
              background-color: #fff;
              width: 95px;
              height: 30px;
              border-radius: 30px;
              color: #333;

              .txt {
                display: block;
                color: #333;
                margin-left: 5px;
              }
            }
          }

          .update-vip {
            position: absolute;
            right: -60px;
            bottom: 5px;
          }
        }
      }
    }

    .message-right {
      padding: 10px 0;

      .message-main {
        display: flex;
        flex-direction: row-reverse;

        .avatar {
          width: 40px;
          height: 40px;
          object-fit: cover;
          border-radius: 50%;
          margin-left: 10px;
        }

        .avatar-icon {
          width: 40px;
          height: 40px;
          border-radius: 50%;
          background-color: @primary-color;
          color: #fff;
          display: flex;
          justify-content: center;
          align-items: center;
          margin-left: 10px;
          font-size: 22px;
        }

        .message-content {
          position: relative;
          padding-left: 40px;

          .message-card {
            background-color: #fff;
            padding: 10px 20px;
            border-radius: 8px;

            .message-text {
              white-space: pre-wrap;
            }
          }

          .message-copy {
            background-color: #fff;
            width: 30px;
            height: 30px;
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            cursor: pointer;
            position: absolute;
            left: 0;
            bottom: 0;
            color: #999;

            &:hover {
              color: #333;
            }
          }
        }
      }
    }

    .recommend-list {
      width: 60%;
      height: 100%;
      margin: 0 auto;
      display: flex;
      justify-content: center;
      padding-top: 40px;

      .refresh-button {
        position: absolute;
        top: 5px;
        right: 0;
        font-size: 18px;
      }

      .recommend-title {
        text-align: center;
        font-size: 28px;
        font-weight: bold;
      }

      .cate-list {
        width: 100%;
        display: flex;
        margin-top: 20px;

        .cate-column {
          flex: 1;
          padding: 0 15px;

          .cate-title {
            display: flex;
            justify-content: center;
            align-items: center;
            margin: 30px 0;
            font-size: 20px;

            .cate-icon {
              width: 28px;
              height: 28px;
              object-fit: cover;
              margin-right: 10px;
            }
          }

          .cate-item-card {
            background-color: #fff;
            font-size: 16px;
            border-radius: 8px;
            margin-top: 15px;
            padding: 15px 20px;
            cursor: pointer;
            box-shadow: 0 5px 20px #eee;
            transition: 0.2s ease;

            .cate-item-content {
              overflow: hidden;
              text-overflow: ellipsis;
              display: -webkit-box;
              -webkit-line-clamp: 2;
              -webkit-box-orient: vertical;
            }

            &:hover {
              background-color: @primary-color;
              color: #fff;
              // background-color: #f7f0ff;
              // color: @primary-color;
            }
          }
        }
      }
    }
  }

  .chat-footer {
    padding-top: 10px;
    .button-list {
      margin-bottom: 12px;
    }

    .chat-input-wrap {
      display: flex;
      align-items: center;

      .chat-input {
        flex: 1;
        border: none;
        outline: none;
        resize: none;
        border-radius: 8px;
        height: 60px;
        line-height: 20px;
        padding: 10px 20px;
        box-shadow: 0 5px 25px #193e7b14;

        &:focus-visible {
          border: none;
          outline: none;
        }
      }

      .chat-submit-button {
        border-radius: 4px;
        margin-left: 10px;
      }
    }

    .disclaimer-wrap {
      color: #999;
      font-size: 12px;
      cursor: pointer;
      display: inline-block;
      width: 70px;
      height: 36px;
      line-height: 36px;

      &:hover {
        color: @primary-color;
      }
    }
  }
}
</style>

<style lang="less">
.message-markdown-wrap {
  > *:first-child {
    margin-top: 0 !important;
  }
  table {
    border: 1px solid #ccc;
    width: 100%;
    margin-bottom: 10px;
  }
  table td,
  table th {
    border-bottom: 1px solid #ccc;
    border-right: 1px solid #ccc;
    padding: 6px 13px;
  }
  table th {
    text-align: center;
    background: #dee8ee;
  }
  table th:last-child {
    border-right: none;
  }
  table td:last-child {
    border-right: none;
  }

  table tr:last-child td {
    border-bottom: none;
  }
  tr:nth-child(even) {
    background: #eff3f5;
  }
  /* blockquote 样式 */
  blockquote {
    display: block;
    border-left: 8px solid #d0e5f2;
    padding: 5px 10px;
    margin: 10px 0;
    line-height: 1.4;
    font-size: 100%;
    background-color: #f1f1f1;
  }
  p {
    margin-top: 0;
    margin-bottom: 16px;
    white-space: pre-wrap;
  }
  /* ul ol 样式 */
  ul,
  ol {
    margin: 10px 0 10px 0px;
    padding-left: 2em;
  }
  li > p {
    margin-top: 16px;
  }
  h3 {
    font-size: 1.25em;
    font-weight: 600;
  }
  h4 {
    font-weight: 600;
    font-size: 1em;
  }
  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    margin-top: 24px;
    margin-bottom: 16px;
    font-weight: 600;
    line-height: 1.25;
  }

  pre {
    margin: 0;
  }
}
</style>
